<template>
  <div class="container">
    <!-- 头部区域 -->
    <div class="header-section">
      <div class="header-left">
        <h2 class="project-title" @click="refreshData()">{{ projectName || '加载中...' }}</h2>
        <!-- 导航路径显示 -->
        <div class="navigation-path" v-if="navigationHistory.length > 0">
          <span class="path-label">：</span>
          <span v-for="(item, index) in navigationHistory" :key="index" class="path-item"
                :class="{ 'current-level': index === navigationHistory.length - 1 }" @click="navigateToLevel(index)">
            {{ item.name || item.id }}
            <el-icon v-if="index < navigationHistory.length - 1" class="path-separator">
              <ArrowRight/>
            </el-icon>
          </span>
        </div>
      </div>
      <div class="header-right">
        <div class="header-controls">
          <!-- 回退按钮 -->
          <el-button v-if="navigationHistory.length > 1" @click="goBack" size="small" style="margin-right: 16px;"
                     type="primary" plain>
            <el-icon>
              <ArrowLeft/>
            </el-icon>
            返回上级
          </el-button>
          <el-button @click="openColumnConfig" size="small" style="margin-right: 16px;" type="primary" plain>
            <el-icon style="margin-right: 4px;">
              <Setting/>
            </el-icon>
            配置
          </el-button>
          <!-- 货币切换器 -->
          <el-select v-model="currentCurrency" @change="handleCurrencyChange" size="small"
                     style="width: 120px; margin-right: 16px;" placeholder="选择货币">
            <el-option v-for="(name, code) in currencyNames" :key="code" :label="`${currencySymbols[code]} ${name}`"
                       :value="code">
            </el-option>
          </el-select>
          <!-- 汇率管理按钮 -->
          <el-button @click="openExchangeRateDialog" size="small" style="margin-right: 16px;" type="info" plain>
            <el-icon style="margin-right: 4px;">
              <Setting/>
            </el-icon>
            汇率
          </el-button>
          <!-- 导出按钮 -->
          <el-button @click="openExportDialog" size="small" style="margin-right: 16px;" type="success" plain>
            <el-icon style="margin-right: 4px;">
              <Download/>
            </el-icon>
            导出
          </el-button>
          <!-- 导入按钮 -->
          <el-button @click="openImportDialog" size="small" style="margin-right: 16px;" type="warning" plain>
            <el-icon style="margin-right: 4px;">
              <Upload/>
            </el-icon>
            导入
          </el-button>
          <el-input v-model="searchKeyword" placeholder="搜索..." size="small" style="width: 200px;" clearable>
            <template #prefix>
              <el-icon>
                <Search/>
              </el-icon>
            </template>
          </el-input>
        </div>
      </div>
    </div>
    <div class="table-wrapper" @contextmenu="handleTableContextMenu">
      <!-- 表格主体 -->
      <el-table
          :key="`table-${tableData.length}-${tableData.map((r, idx) => `${r.id || r.rowId || idx}-${idx}`).join('-')}`"
          :data="filteredTableData" style="width: 100%; border-top: none; height: 100%" :row-style="getRowStyle"
          @row-contextmenu="handleRowContextMenu" @row-click="handleRowClick" :row-class-name="getRowClassName"
          :span-method="arraySpanMethod" border :resizable="true">
        <el-table-column v-for="column in displayedColumns" :label="column.label" :key="column.prop" :prop="column.prop"
                         :width="column.width" :fixed="column.fixed" :sortable="column.sortable"
                         :resizable="column.resizable"
                         :align="column.align">
          <template #default="{ row }">
            <div v-if="column.prop === 'color'" class="color-cell">
              <el-color-picker v-model="row.color" size="small" show-alpha
                               :predefine="['#409EFF', '#67C23A', '#E6A23C', '#F56C6C', '#909399', '#303133', 'rgba(255,255,255,0)']"
                               @active-change="(color) => onActiveColorChange(row, color)"
                               @change="onColorChange(row, tableData.indexOf(row))"/>
            </div>
            <div v-else-if="column.prop === 'rowId'" class="editable-cell drag-handle"
                 :class="{ 'editing-cell': isCellEditing(tableData.indexOf(row), column.prop) }"
                 @click="startEditing(tableData.indexOf(row), column.prop)"
                 @dblclick="skipToChildren(tableData.indexOf(row), column.prop)">
              <el-icon>
                <Sort/>
              </el-icon>
              <span v-if="column.prop === 'rowId' && !isSubSection(row, column.prop)" style="margin-left: 10px">{{
                  row[column.prop]
                }}</span>
            </div>
            <div v-else class="editable-cell"
                 :class="{ 'editing-cell': isCellEditing(tableData.indexOf(row), column.prop) }"
                 @click="startEditing(tableData.indexOf(row), column.prop)"
                 @dblclick="skipToChildren(tableData.indexOf(row), column.prop)">
              <el-input
                  v-if="isCellEditing(tableData.indexOf(row), column.prop) && isEditable(row, column.prop, tableData.indexOf(row)) && column.prop !== 'uint'"
                  :model-value="getEditingValue(row, column.prop)"
                  @update:model-value="setEditingValue(row, column.prop, $event)"
                  @input="handleNumberInput(row, column.prop, $event)" size="small" clearable placeholder="请输入内容"
                  @blur="handleNumberBlur(row, column.prop)" @keydown.enter="stopEditing" @keydown.esc="cancelEditing"
                  class="full-cell-input budget-input-with-unit" type='text'>
              </el-input>
              <el-select
                  v-else-if="isCellEditing(tableData.indexOf(row), column.prop) && isEditable(row, column.prop, tableData.indexOf(row)) && column.prop === 'uint'"
                  v-model="row[column.prop]" size="small" clearable placeholder="请选择单位" @blur="stopEditing"
                  @change="onUnitChange(row)" class="full-cell-input" filterable allow-create default-first-option
                  :reserve-keyword="false">
                <el-option label="时" value="时"/>
                <el-option label="天" value="天"/>
                <el-option label="月" value="月"/>
              </el-select>
              <span v-else-if="column.prop === 'budget'">{{ formatBudgetValue(row[column.prop]) }}</span>
              <span v-else-if="isCurrencyColumn(column.prop)">{{ formatCurrencyValue(row[column.prop]) }}</span>
              <span v-else>{{ row[column.prop] }}</span>
            </div>
          </template>
        </el-table-column>
      </el-table>
    </div>

    <ul v-if="contextMenu.visible" class="context-menu"
        :style="{ top: contextMenu.y + 'px', left: contextMenu.x + 'px' }" style="position: fixed; z-index: 9999;">
      <li @click="addNewRow">
        <el-icon>
          <Plus/>
        </el-icon>
        新增行
      </li>
      <li @click="addSubSectionByContext">
        <el-icon>
          <FolderAdd/>
        </el-icon>
        新增小节
      </li>
      <li v-if="tableData.length > 0 && selectedRow" @click="deleteRowByContext" class="danger">
        <el-icon>
          <Delete/>
        </el-icon>
        删除选中行
      </li>
    </ul>

    <!-- 列配置弹窗 -->
    <el-dialog v-model="showColumnConfigDialog" title="列显示配置" width="500px" :close-on-click-modal="false">
      <div class="column-config-content">
        <div class="config-header">
          <span class="config-title">选择要显示的列：</span>

        </div>
        <div class="column-list">
          <div v-for="column in tableColumns" :key="column.prop" class="column-item"
               :class="{ 'disabled': isFixedColumn(column.prop) }">
            <el-checkbox v-model="tempSelectedColumns" :label="column.prop" :disabled="isFixedColumn(column.prop)"
                         @change="handleTempColumnChange">
              {{ column.label }}
              <span v-if="isFixedColumn(column.prop)" class="fixed-label">（固定显示）</span>
            </el-checkbox>
          </div>
        </div>
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="cancelColumnConfig">取消</el-button>
          <el-button type="primary" @click="confirmColumnConfig">确定</el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 汇率管理弹窗 -->
    <el-dialog v-model="showExchangeRateDialog" title="汇率管理" width="600px" :close-on-click-modal="false">
      <div class="exchange-rate-content">
        <div class="rate-header">
          <span class="rate-title">当前汇率设置（以人民币为基准）：</span>
        </div>
        <div class="rate-list">
          <div v-for="(name, code) in currencyNames" :key="code" class="rate-item" v-if="code !== 'CNY'">
            <div class="rate-label">
              <span class="currency-symbol">{{ currencySymbols[code] }}</span>
              <span class="currency-name">{{ name }}</span>
            </div>
            <el-input-number v-model="tempExchangeRates[code]" :precision="4" :step="0.0001" :min="0.0001" :max="1000"
                             size="small" style="width: 150px;">
            </el-input-number>
          </div>
        </div>
        <div class="rate-note">
          <el-text type="info" size="small">
            汇率表示1人民币可以兑换多少目标货币
          </el-text>
        </div>
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="cancelExchangeRateConfig">取消</el-button>
          <el-button type="primary" @click="confirmExchangeRateConfig">确定</el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 导出弹窗 -->
    <el-dialog v-model="showExportDialog" title="导出数据" width="500px" :close-on-click-modal="false">
      <div class="export-content">
        <div class="export-option">
          <label class="export-label">导出格式：</label>
          <el-radio-group v-model="exportFormat">
            <el-radio label="xlsx">Excel (.xlsx)</el-radio>
            <el-radio label="csv">CSV (.csv)</el-radio>
            <el-radio label="pdf">PDF (.pdf)</el-radio>
          </el-radio-group>
        </div>
        <div class="export-option">
          <label class="export-label">导出范围：</label>
          <el-radio-group v-model="exportRange">
            <el-radio label="all">全部数据</el-radio>
            <el-radio label="filtered">当前筛选结果</el-radio>
            <el-radio label="selected" :disabled="!selectedRow">选中行</el-radio>
          </el-radio-group>
        </div>
        <div class="export-note">
          <el-text type="info" size="small">
            导出数据将使用当前选择的货币显示，只导出普通行（不包含小节行）
          </el-text>
        </div>
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="showExportDialog = false">取消</el-button>
          <el-button type="primary" @click="exportToExcel">导出</el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 导入弹窗 -->
    <el-dialog v-model="showImportDialog" title="导入数据" width="500px" :close-on-click-modal="false">
      <div class="import-content">
        <el-upload class="upload-demo" drag :auto-upload="false" :on-change="handleFileUpload" accept=".xlsx,.xls,.csv"
                   :limit="1">
          <el-icon class="el-icon--upload">
            <upload-filled/>
          </el-icon>
          <div class="el-upload__text">
            将文件拖到此处，或<em>点击上传</em>
          </div>
          <template #tip>
            <div class="el-upload__tip">
              支持 .xlsx、.xls、.csv 格式文件
            </div>
          </template>
        </el-upload>
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="showImportDialog = false">取消</el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 导入预览弹窗 -->
    <el-dialog v-model="showImportPreviewDialog" title="导入预览" width="80%" :close-on-click-modal="false">
      <div class="import-preview-content">
        <div class="preview-header">
          <span class="preview-title">数据预览（前10行）：</span>
          <span class="preview-count">共 {{ importData.length }} 条数据</span>
        </div>
        <div class="preview-table">
          <el-table :data="importPreviewData" border style="width: 100%" max-height="400">
            <el-table-column v-for="column in tableColumns.filter(col => col.prop !== 'color')" :key="column.prop"
                             :prop="column.prop" :label="column.label" :width="column.width" show-overflow-tooltip>
              <template #default="{ row, $index }">
                <el-input v-if="column.prop === 'budget'" v-model="row[column.prop]" type="number" size="small"
                          placeholder="请输入预算" @blur="validateBudgetValue(row, $index)">
                </el-input>
                <el-input v-else-if="column.prop === 'rowId'" v-model="row[column.prop]" size="small"
                          placeholder="请输入行ID" @blur="validateRowId(row, $index)">
                </el-input>
                <el-input v-else v-model="row[column.prop]" size="small" :placeholder="`请输入${column.label}`">
                </el-input>
              </template>
            </el-table-column>
          </el-table>
        </div>
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="cancelImport">取消</el-button>
          <el-button type="primary" @click="confirmImport">确认导入</el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 底部总计区域 -->
    <div class="footer-section">
      <div class="total-row">
        <div class="total-row total-with-spare">
          <div class="total-label">总预算（含备用金）:</div>
          <div class="total-value">{{ formatBudgetValue(totalBudgetWithSpare) }}</div>
        </div>
        <div class="total-label variance">备用金:</div>
        <div class="total-value spare-money">
          <span>{{ formatBudgetValue(spareMoney) }}</span>
          <el-popover placement="top" :width="300" trigger="click" popper-class="spare-money-popover">
            <template #reference>
              <el-button type="primary" size="small" circle class="edit-ratio-btn">
                <el-icon>
                  <Setting/>
                </el-icon>
              </el-button>
            </template>
            <div class="spare-money-editor">
              <div class="editor-title">调整备用金比例</div>
              <div class="editor-content">
                <el-slider v-model="spareMoneyRatio" :min="0" :max="0.5" :step="0.01"
                           :format-tooltip="(val) => `${(val * 100).toFixed(0)}%`" show-input
                           :show-input-controls="false"
                           input-size="small" @change="updateSpareMoneyRatio">
                  <template #input>
                    <el-input-number v-model="spareMoneyRatio" :min="0" :max="0.5" :step="0.01" :precision="2"
                                     size="small" :controls="false" @change="updateSpareMoneyRatio">
                      <template #suffix>%</template>
                    </el-input-number>
                  </template>
                </el-slider>
              </div>
            </div>
          </el-popover>
        </div>
      </div>
      <div class="total-row variance" v-if="selectedColumns.includes('budget')">
        <div class="total-label">预算总计:</div>
        <div class="total-value">{{ formatBudgetValue(totalBudget) }}</div>
      </div>
      <div class="total-row" v-if="selectedColumns.includes('actualPay')">
        <div class="total-label">实际总计:</div>
        <div class="total-value">{{ formatBudgetValue(totalActual) }}</div>
      </div>
      <div class="total-row variance"
           v-if="selectedColumns.includes('budget') && selectedColumns.includes('actualPay')">
        <div class="total-label">差异:</div>
        <div class="total-value" :class="{ 'positive': totalVariance >= 0, 'negative': totalVariance < 0 }">
          {{ formatBudgetValue(totalVariance) }}
        </div>
      </div>
    </div>

  </div>
</template>


<script setup>
import {computed, nextTick, onMounted, onUnmounted, reactive, ref} from 'vue'
import {
  deleteBudget,
  queryBudget,
  saveBudget,
  saveOrUpdateBudgets,
  updateBudget,
  updateBudgetSort
} from '@/api/budgetApi'
import {getTemplateColumns} from '@/api/templateApi'
import {getProject, updateProject} from '@/api/projectApi'
import {ElMessage, ElMessageBox} from 'element-plus'
import {
  ArrowLeft,
  ArrowRight,
  Delete,
  Download,
  FolderAdd,
  Plus,
  Search,
  Setting,
  Sort,
  Upload,
  UploadFilled
} from '@element-plus/icons-vue'
import Sortable from 'sortablejs';
import {useStore} from 'vuex'
import * as XLSX from 'xlsx'
import '@/assets/font/AlibabaPuHuiTi-3-45-Light-normal.js'
import {saveAs} from 'file-saver'
import {jsPDF} from 'jspdf'
import autoTable from 'jspdf-autotable'


const store = useStore()
// 用户ID
const userId = computed(() => {
  return store.getters.getUserId;
});

// 货币相关
const currentCurrency = ref(store.getters.getCurrentCurrency);
const currencySymbols = computed(() => store.state.currencySymbols);
const currencyNames = computed(() => store.state.currencyNames);
const exchangeRates = computed(() => store.getters.getExchangeRates);

// 接收传递的模板和项目参数
const props = defineProps({
  params: {
    type: Object,
    required: true
  }
})

// 预算基本信息
const budgetParam = reactive({
  projectId: props.params.projectId,
  templateId: props.params.templateId,
  parentId: 0,
  type: 0,
  color: '#fff',
  rowId: '',
  hasChild: '0',
  userId: userId.value,
  budget: 0.0,
})

// 备用金比例
const spareMoneyRatio = ref(0.0);
// 备用金
const spareMoney = ref(0.0);
// 总预算（含备用金）
const totalBudgetWithSpare = ref(0.0);

// 查询参数
const queryParams = reactive({
  projectId: props.params.projectId,
  templateId: props.params.templateId,
  parentId: 0,
  showChildren: false,
})

// 表格列配置
const tableColumns = ref([])
// 表格数据
const tableData = ref([])
// 选中的行
const selectedRow = ref(null)

// 头部相关数据
const projectName = ref('')
const searchKeyword = ref('')
const selectedColumns = ref([])

// 列配置弹窗相关
const showColumnConfigDialog = ref(false)
const tempSelectedColumns = ref([])

// 汇率管理弹窗相关
const showExchangeRateDialog = ref(false)
const tempExchangeRates = ref({})

// 导入导出相关
const showExportDialog = ref(false)
const showImportDialog = ref(false)
const showImportPreviewDialog = ref(false)
const importFile = ref(null)
const importData = ref([])
const importPreviewData = ref([])
const exportFormat = ref('xlsx')
const exportRange = ref('all') // all, filtered, selected

// 导航历史管理
const navigationHistory = ref([])

// 获取横向合并起始列的索引与prop（从第3列开始，直到budget列前一列）
const getMergeStartColIndex = () => {
  const budgetIndex = tableColumns.value.findIndex(col => col.prop === 'budget')
  const startIndex = 2 // 第3列
  if (budgetIndex === -1 || budgetIndex <= startIndex) return -1
  for (let i = startIndex; i < budgetIndex; i++) {
    const prop = tableColumns.value[i]?.prop
    if (prop && prop !== 'color' && prop !== 'rowId') return i
  }
  return -1
}
const getMergeStartProp = () => {
  const idx = getMergeStartColIndex()
  return idx !== -1 ? tableColumns.value[idx].prop : null
}

// 获取合并单元格显示值
const getMergedCellValue = (row) => {
  const prop = getMergeStartProp()
  if (!prop) return ''
  return row[prop]
}

// 设置合并单元格显示值（persist=true时尝试持久化到后端）
const setMergedCellValue = async (row, text, persist = false) => {
  const prop = getMergeStartProp()
  if (!prop) return
  row[prop] = text
  if (!persist) return
  if (!row.id) return // 新增行可能还没有后端生成的id
  const column = tableColumns.value.find(c => c.prop === prop)
  const columnId = column?.id
  let cellInfo = getCellInfo(row, prop)
  if (!cellInfo) {
    cellInfo = {
      id: '',
      budgetId: row.id,
      columnsId: columnId,
      rowId: row.rowId,
      content: text,
    }
  } else {
    cellInfo.content = text
  }
  await saveOrUpdateBudgets([cellInfo])
}

const isSubSection = (row, prop) => {
  if (row.rowId !== null && prop === 'rowId') {
    // 只通过type=1判断是否为小节行
    return row.type === 1;
  }
  return false;
}

// 获取项目信息
const getProjectInfo = async () => {
  const res = await getProject(queryParams.projectId)
  if (res && res.name) {
    projectName.value = res.name
    // 备用金比例
    spareMoneyRatio.value = res.spareMoneyRatio || 0.0;
    // 备用金
    spareMoney.value = res.budgetSum * spareMoneyRatio.value;
    // 总预算（含备用金）
    totalBudgetWithSpare.value = res.budgetSum + spareMoney.value;
  } else {
    projectName.value = '未命名项目'
  }
}

// 重新刷新数据
const refreshData = async () => {
  queryParams.parentId = 0
  navigationHistory.value = []
  await getTableData();
}

// 根据模板获取所有列
const getFields = async () => {
  const res = await getTemplateColumns(queryParams.templateId)
  if (res.templateColumns && Array.isArray(res.templateColumns)) {
    // 转换为el-table的列配置
    tableColumns.value = res.templateColumns.map(field => {

      return {
        id: field.id,
        prop: field.column,
        label: field.columnName,
        columnType: field.columnType, // 保存列的数据类型
        width: 'auto',
        fixed: false,
        resizable: field.fixed === 0, // 允许调整列宽
        sortable: field.columnType === 'int' || field.columnType === 'double' || field.columnType === 'float' || field.columnType === 'long',
        align: field.columnType === 'int' || field.columnType === 'double' || field.columnType === 'float' || field.columnType === 'long' ? 'right' : 'left'
      };
    })

    // 添加固定的预算列
    tableColumns.value.push({
      prop: 'budget',
      label: '预算',
      columnType: 'double', // 预算列为double类型
      width: 150,
      fixed: false,
      resizable: true, // 预算列可以调整宽度
      sortable: true,
      align: 'right'
    })

    // 添加固定的 # ID 列（显示 rowId） 和 颜色列
    tableColumns.value.unshift({
      prop: 'color',
      label: '颜色',
      columnType: 'text', // 颜色列为文本类型
      fixed: true,
      resizable: false, // 颜色列不可调整宽度
      width: 60,
      align: 'center'
    }, {
      prop: 'rowId',
      label: '# ID',
      columnType: 'text', // ID列为文本类型
      width: 120,
      fixed: true,
      resizable: false, // ID列不可调整宽度
      sortable: false,
      align: 'center'
    })
    // 初始化选中的列
    selectedColumns.value = tableColumns.value.map(col => col.prop)
    // 初始化临时选中的列
    tempSelectedColumns.value = [...selectedColumns.value]
  }
}

// 获取表格项数据
const getTableData = async () => {
  try {
    // 获取项目信息，确保备用金数据随表格数据更新
    await getProjectInfo();

    const res = await queryBudget(queryParams);

    if (res && Array.isArray(res)) {
      // 将API返回的数据格式转换为表格需要的格式
      tableData.value = res.map((item, index) => {
        const row = {
          id: item.id,
          rowId: item.rowId,
          type: item.type,
          parentId: item.parentId,
          color: item.color,
          content: item.content,
          budget: item.budget,
          visible: item.visible,
          fixed: item.fixed,
          hasChild: item.hasChild,
          // 确保sort字段不为null，如果为null或undefined则使用index+1作为默认值
          sort: (item.sort !== null && item.sort !== undefined) ? item.sort : (index + 1),
          colMap: item.colNameToContent
        };

        // 映射 colNameToContent 中的内容到对应的列
        if (item.colNameToContent) {
          Object.keys(item.colNameToContent).forEach(colName => {
            const colData = item.colNameToContent[colName];
            if (colData && colData.content !== undefined) {
              row[colName] = colData.content;
            }
          });
        }

        // 设置单位字段的初始值
        if (!row.uint) {
          row.uint = '时'; // 默认时间单位
        }
        row.oldUnit = row.uint; // 记录当前单位，用于换算

        // 设置小节合并列
        if (item.type === 1) {
          setMergedCellValue(row, item.content)
        }

        // 如果rowId还是旧格式，尝试转换为新格式
        if (row.rowId && row.rowId.includes('-')) {
          // 检查是否是层级格式（如"111-211"），如果不是则转换
          const parts = row.rowId.split('-');
          if (parts.length === 3) {
            // 旧格式："1-1-2" 转换为新格式："112"
            const level = parts[0];
            const section = parts[1];
            const item = parts[2] === (Math.pow(2, 31) - 1).toString() ? '9' : parts[2];
            row.rowId = `${level}${section}${item}`;
          }
        }

        return row;
      });

      // 检查并修复sort字段为null的情况
      let hasNullSort = false;
      tableData.value.forEach((row, index) => {
        if (row.sort === null || row.sort === undefined) {
          row.sort = index + 1;
          hasNullSort = true;
        }
      });

      // 按sort字段排序，确保sort为null时使用默认值
      tableData.value.sort((a, b) => {
        const sortA = (a.sort !== null && a.sort !== undefined) ? a.sort : 999999;
        const sortB = (b.sort !== null && b.sort !== undefined) ? b.sort : 999999;
        return sortA - sortB;
      });

      // 检查是否需要初始化sort字段
      await checkAndInitializeSortFields();

      // 强制触发Vue重新渲染
      await nextTick();

      // 数据更新完成后重新初始化拖拽功能
      setTimeout(() => {
        initRowDrag();
      }, 100);

    } else {
      tableData.value = [];
    }
  } catch (error) {
    console.error('获取表格数据失败:', error);
    ElMessage.error('获取数据失败');
    tableData.value = [];
  }
}

// 在表格渲染后初始化拖拽
const initRowDrag = () => {
  const wrapper = document.querySelector('.el-table__body-wrapper tbody');
  if (wrapper && wrapper.Sortable) {
    wrapper.Sortable.destroy();
  }
  if (!wrapper) return;

  Sortable.create(wrapper, {
    animation: 150,
    handle: '.drag-handle',
    onEnd: async ({newIndex, oldIndex}) => {
      if (newIndex === oldIndex) return;

      try {
        // 保存原始数据用于错误恢复
        const originalData = [...tableData.value];

        // 更新本地tableData的顺序，与DOM保持一致
        const reorderedData = [...tableData.value];
        const [removed] = reorderedData.splice(oldIndex, 1);
        reorderedData.splice(newIndex, 0, removed);

        // 立即更新本地数据，确保UI与数据同步
        tableData.value = reorderedData;

        // 生成排序更新数据
        const sortUpdates = [];
        tableData.value.forEach((row, index) => {
          if (row.id && row.id !== '') {
            const newSort = index + 1;
            // 更新本地sort值
            row.sort = newSort;
            sortUpdates.push({
              id: row.id,
              sort: newSort
            });
          }
        });

        // 强制触发Vue重新渲染
        await nextTick();

        // 异步更新后端排序
        if (sortUpdates.length > 0) {
          await updateBudgetSortDirect(sortUpdates);
          // 重新获取数据
          await getTableData();
          ElMessage.success('排序已更新');
        }

        // DOM更新后重新初始化拖拽功能
        setTimeout(() => {
          initRowDrag();
        }, 100);

      } catch (error) {
        ElMessage.error('排序更新失败');

        // 出错时恢复原始数据
        tableData.value = originalData;
        await nextTick();

        // 重新初始化拖拽功能
        setTimeout(() => {
          initRowDrag();
        }, 100);
      }
    }
  });
};

// 更新排序字段（用于非拖拽场景）
const updateSortOrder = async () => {
  // 过滤出有有效ID的行，并为其重新分配排序号
  const validRows = tableData.value.filter(row => row.id && row.id !== '');

  if (validRows.length === 0) {
    return;
  }

  const sortUpdates = validRows.map((row, index) => {
    return {
      id: row.id,
      sort: index + 1
    };
  });

  // 更新本地数据
  tableData.value.forEach((row, index) => {
    row.sort = index + 1;
  });

  // 批量更新后端排序
  await updateBudgetSort(sortUpdates);
};

// 检查并初始化sort字段
const checkAndInitializeSortFields = async () => {
  const needsUpdate = [];
  let hasNullSort = false;

  tableData.value.forEach((row, index) => {
    if (row.sort === null || row.sort === undefined) {
      const newSort = index + 1;
      row.sort = newSort;
      needsUpdate.push({
        id: row.id,
        sort: newSort
      });
      hasNullSort = true;
    }
  });

  if (hasNullSort && needsUpdate.length > 0) {
    await updateBudgetSortDirect(needsUpdate);
  }
};

// 直接批量更新排序（用于拖拽场景）
const updateBudgetSortDirect = async (sortUpdates) => {
  await updateBudgetSort(sortUpdates);
};

// 改变表格颜色
const getRowStyle = ({row}) => {
  return {backgroundColor: row.color || '#ffffff'}
}

const handleGlobalClick = (event) => {
  // 如果没有正在编辑的单元格，直接返回
  if (editingCell.rowIndex === null || editingCell.prop === null) {
    return
  }

  // 获取当前编辑的单元格元素
  const editingCellElement = event.target.closest('.editable-cell.editing-cell')

  // 如果点击的不是正在编辑的单元格（或其内部元素），则退出编辑
  if (!editingCellElement) {
    stopEditing()
  }
}

onMounted(async () => {
  document.addEventListener('click', handleGlobalClick);
  await getProjectInfo() // 获取项目信息
  await getFields() // 获取列配置
  await getTableData() // 获取表格数据
  // 初始化行拖拽
  await nextTick(() => {
    initRowDrag();
  });
})

onUnmounted(() => {
  document.removeEventListener('click', handleGlobalClick);
});

// 新增小节
const addSubSectionByContext = async () => {
  const newRow = createSubEmptyRow()
  const currentRow = getCurrentRow()
  if (currentRow) {
    const rowIndex = tableData.value.findIndex(r => r === currentRow)
    budgetParam.rowId = newRow.rowId
    budgetParam.type = 1
    budgetParam.budget = newRow.budget
    budgetParam.content = getMergedCellValue(newRow)
    budgetParam.sort = newRow.sort // 添加sort字段
    const res = await saveBudget(budgetParam)
    // 如果保存返回了id，则写回并尝试持久化合并文本
    if (res && res.id) {
      newRow.id = res.id
      const mergedText = `${newRow.rowId} - ${newRow.rowId} 小节`
      await setMergedCellValue(newRow, mergedText, true)
    }
    if (rowIndex >= 0) {
      // 在选中行后插入
      tableData.value.splice(rowIndex + 1, 0, newRow)
    } else {
      // 末尾插入
      tableData.value.push(newRow)
    }
    // 更新所有项的排序
    await updateSortOrder();
  } else {
    // 末尾插入
    budgetParam.rowId = newRow.rowId
    budgetParam.type = 1
    budgetParam.budget = newRow.budget
    budgetParam.content = getMergedCellValue(newRow)
    budgetParam.sort = newRow.sort
    const res = await saveBudget(budgetParam)

    // 如果保存返回了id，则写回并尝试持久化合并文本
    if (res && res.id) {
      newRow.id = res.id
      const mergedText = `${newRow.rowId} - ${newRow.rowId} 小节`
      await setMergedCellValue(newRow, mergedText, true)
    }

    tableData.value.push(newRow)
    // 更新所有项的排序
    await updateSortOrder();
  }

  // 重新获取数据
  await getTableData();

  // 数据更新完成后重新初始化拖拽功能
  await nextTick();
  setTimeout(() => {
    initRowDrag();
  }, 100);
  ElMessage.success('添加成功')
  hideContextMenu()
}

// 获取当前选中的行数据
const getCurrentRow = () => {
  if (selectedRow.value) {
    return selectedRow.value
  }
  return tableData.value[tableData.value.length - 1];
}

// 删除行
const deleteRowByContext = async () => {
  if (tableData.value.length === 0) {
    hideContextMenu()
    return
  }
  // 获取当前行
  const currentRow = getCurrentRow()
  if (currentRow) {
    const rowIndex = tableData.value.findIndex(r => r === currentRow)
    if (rowIndex >= 0) {
      await deleteBudget(currentRow.id)
      tableData.value.splice(rowIndex, 1)
      ElMessage.success('删除当前行成功')
      // 清除选中状态
      selectedRow.value = null
    }
  } else {
    // 如果没有选中的行，删除最后一行
    await deleteBudget(tableData.value[tableData.value.length - 1].id)
    tableData.value.splice(tableData.value.length - 1, 1)
    ElMessage.success('删除末尾行成功')
  }

  // 重新获取数据
  await getTableData();

  // 删除行后重新初始化拖拽功能
  await nextTick();
  setTimeout(() => {
    initRowDrag();
  }, 100);

  hideContextMenu()
}

// 回退到上一级
const goBack = async () => {
  if (navigationHistory.value.length > 1) {
    // 移除当前级别
    navigationHistory.value.pop();
    // 获取上一级的信息
    const previousLevel = navigationHistory.value[navigationHistory.value.length - 1];
    // 更新查询参数
    queryParams.parentId = previousLevel.parentId;
    budgetParam.budgetId = previousLevel.budgetId;
    // 重新获取数据
    await getTableData();
    // 数据更新完成后重新初始化拖拽功能
    await nextTick();
    setTimeout(() => {
      initRowDrag();
    }, 100);
  }
}

// 导航到指定级别
const navigateToLevel = async (levelIndex) => {
  if (levelIndex >= 0 && levelIndex < navigationHistory.value.length) {
    // 截取到指定级别的历史
    navigationHistory.value = navigationHistory.value.slice(0, levelIndex + 1);
    // 获取指定级别的信息
    const targetLevel = navigationHistory.value[levelIndex];
    // 更新查询参数
    queryParams.parentId = targetLevel.parentId;
    budgetParam.budgetId = targetLevel.budgetId;
    // 重新获取数据
    await getTableData();
    // 数据更新完成后重新初始化拖拽功能
    await nextTick();
    setTimeout(() => {
      initRowDrag();
    }, 100);
  }
}

// 编辑的单元格
const editingCell = reactive({rowIndex: null, prop: null})

const contextMenu = reactive({
  visible: false,
  x: 0,
  y: 0,
  rowIndex: -1
})

// 行右键菜单
const handleRowContextMenu = (row, column, event) => {
  event.preventDefault()
  // 设置选中的行
  selectedRow.value = row
  contextMenu.visible = true
  contextMenu.x = event.clientX
  contextMenu.y = event.clientY
  contextMenu.rowIndex = tableData.value.findIndex(r => r === row)
  document.addEventListener('click', hideContextMenu)
}

// 行点击事件
const handleRowClick = (row, column, event) => {
  selectedRow.value = row
}

// 获取行的类名
const getRowClassName = ({row, rowIndex}) => {
  let className = '';

  // 如果是选中的行
  if (row === selectedRow.value) {
    className += ' selected-row';
  }

  // 如果是小节行（只通过type=1判断）
  if (row && row.type === 1) {
    className += ' section-row';
  }
  return className.trim();
}

// 单元格合并方法
const arraySpanMethod = ({row, column, rowIndex, columnIndex}) => {
  // 判断是否小节行（只通过type=1判断）
  const isSection = row && row.type === 1;
  if (!isSection) {
    return [1, 1];
  }

  // 第1列(color)与第2列(rowId)不合并
  if (columnIndex === 0 || columnIndex === 1) {
    return [1, 1];
  }

  // budget列不参与合并
  const budgetColIndex = tableColumns.value.findIndex(col => col.prop === 'budget');
  if (budgetColIndex === -1) {
    return [1, 1];
  }

  // 仅从第3列开始合并，一直到budget前一列
  const startMergeColIndex = 2; // 第三列（0-based）
  const endMergeColIndexExclusive = budgetColIndex; // 不包含budget
  const mergeColspan = Math.max(endMergeColIndexExclusive - startMergeColIndex, 0);

  // 如果预算列就在第三列或之前，则不合并
  if (mergeColspan <= 1) {
    return [1, 1];
  }

  // 第三列为合并起点：设置colspan，其他被覆盖列隐藏
  if (columnIndex === startMergeColIndex) {
    return [1, mergeColspan];
  }

  // 位于合并区间内的列隐藏
  if (columnIndex > startMergeColIndex && columnIndex < endMergeColIndexExclusive) {
    return [0, 0];
  }

  // budget列及其之后不合并
  return [1, 1];
}

// 表格右键菜单
const handleTableContextMenu = (event) => {
  event.preventDefault()
  const target = event.target
  const tableRow = target.closest('.el-table__row')
  if (tableRow) {
    return
  }
  // 清除选中状态
  clearSelection()
  contextMenu.visible = true
  contextMenu.x = event.clientX
  contextMenu.y = event.clientY
  contextMenu.rowIndex = tableData.value.length
  document.addEventListener('click', hideContextMenu)
}

// 隐藏右键菜单
const hideContextMenu = () => {
  contextMenu.visible = false;
  contextMenu.rowIndex = -1;

  document.removeEventListener('click', hideContextMenu)
}

// 清除选中状态
const clearSelection = () => {
  selectedRow.value = null
}

const createSubEmptyRow = () => {
  const currentRow = getCurrentRow()
  let rowIndex = -1

  if (currentRow) {
    rowIndex = tableData.value.findIndex(r => r === currentRow)
  } else {
    rowIndex = contextMenu.rowIndex
  }

  const row = {}
  tableColumns.value.forEach(col => {
    row[col.prop] = ''
  })

  // 设置默认单位为"时"
  row.uint = '时'

  // 设置新小节行的sort值
  if (rowIndex >= 0 && rowIndex < tableData.value.length) {
    // 在指定位置插入，sort值为后一位的sort值
    row.sort = tableData.value[rowIndex].sort + 0.5;
  } else {
    // 在末尾添加，sort值为最大值+1
    const maxSort = tableData.value.length > 0 ? Math.max(...tableData.value.map(r => r.sort || 0)) : 0;
    row.sort = maxSort + 1;
  }

  const preRow = tableData.value[rowIndex];
  if (preRow && preRow.rowId) {
    // 创建当前小节rowId - 新的ID生成策略
    const levelNum = convertToInteger(preRow, 0); // 层级编号
    let sectionNum = convertToInteger(preRow, 1); // 小节编号
    sectionNum += 1; // 新小节编号递增

    // 新建小节行，使用特殊标记999表示小节行
    row.rowId = `${levelNum}${sectionNum}9`;
    row.type = 1; // 标记为小节行

    // 设置合并单元格显示值："rowId - rowId 小节"
    const mergedText = `${row.rowId} - ${row.rowId} 小节`
    // 仅设置前端显示（此时新行可能还没有后端id）
    setMergedCellValue(row, mergedText, false)

    processAfterSubRowId(rowIndex);
    processSubBudget(row, rowIndex);
    return row
  } else {
    ElMessage.success('当前位置前半部分没有预算项，添加小节失败');
  }
}
const processSubBudget = (newRow, rowIndex) => {
  processAfterBudget(rowIndex);
  processBeforeBudget(newRow, rowIndex);
}

const processAfterBudget = (rowIndex) => {
  let sumAfter = 0;
  for (let i = rowIndex + 1; i < tableData.value.length; i++) {
    const row = tableData.value[i];
    // 只通过type=1判断是否为小节行
    if (row.type === 1) {
      row.budget = sumAfter;
      break;
    }
    let budgetNum = 0.00;
    try {
      budgetNum = row.budget;
      if (!Number.isNaN(budgetNum)) sumAfter += budgetNum;
    } catch (err) {
      throw err;
    }
  }
}

const processBeforeBudget = (newRow, rowIndex) => {
  let sumBefore = 0;
  for (let i = rowIndex; i >= 0; i--) {
    const row = tableData.value[i];
    // 只通过type=1判断是否为小节行
    if (row.type === 1) {
      newRow.budget = sumBefore;
      break;
    }
    let budgetNum = 0.00;
    try {
      budgetNum = row.budget;
      if (!Number.isNaN(budgetNum)) sumBefore += budgetNum;

      if (i === 0) {
        newRow.budget = sumBefore;
      }
    } catch (err) {
      throw err;
    }

  }
}
const processAfterSubRowId = (rowIndex) => {
  for (let i = rowIndex + 1; i < tableData.value.length; i++) {
    const row = tableData.value[i];
    const levelNum = convertToInteger(row, 0);
    let sectionNum = convertToInteger(row, 1);
    const itemNum = convertToInteger(row, 2);

    // 只通过type=1判断是否为小节行
    if (row.type === 1) {
      // 如果是小节行，小节编号递增
      sectionNum += 1;
      row.rowId = `${levelNum}${sectionNum}${itemNum}`;
    }
  }
}
const createNormalEmptyRow = () => {
  const row = {
    type: 0,
  }
  tableColumns.value.forEach(col => {
    row[col.prop] = ''
  })

  const currentRow = getCurrentRow()
  let index = -1

  if (currentRow) {
    index = tableData.value.findIndex(r => r === currentRow)
  } else {
    index = tableData.value.length;
  }

  // 设置新行的sort值
  if (index >= 0 && index < tableData.value.length) {
    // 在指定位置插入，sort值为后一位的sort值
    row.sort = tableData.value[index].sort + 0.5;
  } else {
    // 在末尾添加，sort值为最大值+1
    const maxSort = tableData.value.length > 0 ? Math.max(...tableData.value.map(r => r.sort || 0)) : 0;
    row.sort = maxSort + 1;
  }

  const preRow = tableData.value[index];
  if (preRow && preRow.rowId) {
    processNormalRowId(row, preRow);
    processAfterNormalRowIds(index);
  } else if (tableData.value.length !== 0) {
    const tempRow = tableData.value[tableData.value.length - 1];
    const levelNum = convertToInteger(tempRow, 0);
    const sectionNum = convertToInteger(tempRow, 1);
    // 生成新的三位数ID
    row.rowId = `${levelNum}${sectionNum}1`;
    processAfterNormalRowIds(index);
  } else {
    // 如果是子层级，使用父级ID作为前缀
    if (navigationHistory.value.length > 0) {
      const parentId = navigationHistory.value[navigationHistory.value.length - 1].id;
      // 子层级的第一项：父级ID-211
      row.rowId = `${parentId}-211`;
    } else {
      // 默认第一行：第1层级第1小节第1项
      row.rowId = "111";
    }
  }
  return row
}
const processAfterNormalRowIds = (index) => {
  for (let i = index + 1; i < tableData.value.length; i++) {
    const row = tableData.value[i];
    const levelNum = convertToInteger(row, 0);
    const sectionNum = convertToInteger(row, 1);
    let itemNum = convertToInteger(row, 2);

    // 只通过type=1判断是否为小节行
    if (row.type === 1) {
      // 说明遇到小节行停止更新
      break;
    }

    itemNum += 1;
    // 生成新的三位数ID
    row.rowId = `${levelNum}${sectionNum}${itemNum}`;
  }
}
const convertToInteger = (row, index) => {
  try {
    // 处理新的ID格式，支持层级和普通格式
    if (row.rowId.includes('-')) {
      // 层级格式：如 "111-211"
      var rowIds = row.rowId.split("-");
      if (index < rowIds.length) {
        var rowNumber = parseInt(rowIds[index], 10);
        return rowNumber;
      }
      return 0;
    } else {
      // 新格式：如 "111", "121", "211"
      var idStr = row.rowId.toString();
      if (index === 0) {
        // 层级编号：第一位数字
        return parseInt(idStr.charAt(0), 10);
      } else if (index === 1) {
        // 小节编号：第二位数字
        return parseInt(idStr.charAt(1), 10);
      } else if (index === 2) {
        // 项目编号：第三位数字
        return parseInt(idStr.charAt(2), 10);
      }
    }
    return 0;
  } catch (e) {
    throw e
  }
}

const processNormalRowId = (row, preRow) => {
  // 检查是否为子层级（格式如"111-211"）
  if (preRow.rowId.includes('-')) {
    // 处理子层级ID
    const parts = preRow.rowId.split('-');
    const parentPart = parts[0]; // 如"111"
    const childPart = parts[1]; // 如"211"

    const childLevel = parseInt(childPart.charAt(0), 10);
    const childSection = parseInt(childPart.charAt(1), 10);
    let childItem = parseInt(childPart.charAt(2), 10);

    // 如果前一行是小节行（type=1），新行是该小节的第一项
    if (preRow.type === 1) {
      childItem = 1;
    } else {
      childItem += 1;
    }

    row.rowId = `${parentPart}-${childLevel}${childSection}${childItem}`;
  } else {
    // 处理普通三位数ID
    const levelNum = convertToInteger(preRow, 0);
    const sectionNum = convertToInteger(preRow, 1);
    let itemNum = convertToInteger(preRow, 2);

    // 如果前一行是小节行（type=1），则新行是该小节的第一项
    if (preRow.type === 1) {
      itemNum = 1;
    } else {
      itemNum += 1;
    }

    // 生成新的三位数ID
    row.rowId = `${levelNum}${sectionNum}${itemNum}`;
  }
}

// 新增行
const addNewRow = async () => {
  //新增普通行
  const newRow = createNormalEmptyRow()

  const currentRow = getCurrentRow()
  if (currentRow) {
    const rowIndex = tableData.value.findIndex(r => r === currentRow)
    // 保存预算项
    budgetParam.type = newRow.type;
    budgetParam.rowId = newRow.rowId;
    budgetParam.sort = newRow.sort; // 添加sort字段
    // 更新上级 有child
    if (budgetParam.parentId !== 0) {
      await updateBudget({
        id: budgetParam.parentId,
        hasChild: 1
      })
    }
    const res = await saveBudget(budgetParam)

    // 将后端返回的ID赋值给新行
    if (res && res.id) {
      newRow.id = res.id;
    }

    if (rowIndex >= 0) {
      // 在选中行后插入
      tableData.value.splice(rowIndex + 1, 0, newRow)
    } else {
      // 在末尾添加
      tableData.value.push(newRow)
    }
    // 更新所有项的排序
    await updateSortOrder();
  } else {
    // 在末尾添加
    budgetParam.rowId = newRow.rowId;
    budgetParam.sort = newRow.sort;
    const res = await saveBudget(budgetParam)

    // 将后端返回的ID赋值给新行
    if (res && res.id) {
      newRow.id = res.id;
    }

    tableData.value.push(newRow)
    // 更新所有项的排序
    await updateSortOrder();
  }

  // 重新获取数据
  await getTableData();

  // 数据更新完成后重新初始化拖拽功能
  await nextTick();
  setTimeout(() => {
    initRowDrag();
  }, 100);

  ElMessage.success('添加成功');
  hideContextMenu()
}

// 开始编辑
const startEditing = (rowIndex, prop) => {
  editingCell.rowIndex = rowIndex;
  editingCell.prop = prop;
}

// 跳转至子节点
const skipToChildren = async (rowIndex, prop) => {
  const row = tableData.value[rowIndex];
  // 小节不能跳转
  if (row.type === 1) return

  // 更新查询参数
  queryParams.parentId = row.id;
  budgetParam.parentId = row.id;

  // 获取项目名称，优先从name字段获取，如果没有则使用rowId
  const projectName = row.name || row.rowId || `项目-${row.id}`;

  // 更新导航历史，添加当前层级
  const currentLevel = {
    id: row.rowId,
    name: projectName,
    parentId: row.id,
    budgetId: row.id
  };
  navigationHistory.value.push(currentLevel);

  // 子层级的ID会基于当前行的ID，如：111 -> 111-211
  await getTableData();
  // 数据更新完成后重新初始化拖拽功能
  await nextTick();
  setTimeout(() => {
    initRowDrag();
  }, 100);
}

// 添加计算逻辑：数量×单价×倍率=预算，实际费用=预算+加班费+额外费用
const calculateBudgetAndActual = (row) => {
  // 获取相关字段的值，如果不存在则默认为0
  const amount = parseFloat(row.amount) || 0;        // 数量
  const unitPrice = parseFloat(row.unitPrice) || 0;  // 单价
  const ratio = parseFloat(row.ratio) || 1;          // 倍率，默认为1
  const overtimePay = parseFloat(row.overtimePay) || 0;  // 加班费
  const extraPay = parseFloat(row.extraPay) || 0;    // 额外费用

  // 计算预算：数量 × 单价 × 倍率
  const budget = amount * unitPrice * ratio;

  // 计算实际费用：预算 + 加班费 + 额外费用
  const actualPay = budget + overtimePay + extraPay;

  // 更新行数据
  row.budget = budget.toFixed(2);
  row.actualPay = actualPay.toFixed(2);
}

// 在 stopEditing 函数中添加自动计算逻辑
const stopEditing = async () => {
  // 在停止编辑前，获取当前编辑的行索引和属性
  const rowIndex = editingCell.rowIndex;
  const prop = editingCell.prop;
  const columnId = tableColumns.value.find(column => column.prop === prop)?.id;

  // 获取编辑的行
  const row = tableData.value[rowIndex];
  // 获取编辑的单元格内容
  const cell = row[prop];
  if (cell === '' || !cell) return;

  // 如果编辑的是预算列，调用 updateBudget
  if (prop === 'budget') {
    await updateBudget({
      id: row.id,
      budget: parseFloat(cell) || 0
    });
  } else {
    // 其他列调用 saveOrUpdateBudgets
    let cellInfo = getCellInfo(row, prop);
    if (!cellInfo) {
      cellInfo = {
        id: '',
        budgetId: row.id,
        columnsId: columnId,
        rowId: row.rowId,
        content: cell,
        sort: tableData.value.length,
      };
    } else {
      cellInfo.content = cell;
    }

    await saveOrUpdateBudgets([cellInfo]);
  }

  // 清除编辑状态
  editingCell.rowIndex = null;
  editingCell.prop = null;

  // 添加自动计算逻辑
  // 当编辑数量、单价、倍率、加班费、额外费用时，重新计算预算和实际费用
  if (['amount', 'unitPrice', 'ratio', 'overtimePay', 'extraPay'].includes(prop)) {
    calculateBudgetAndActual(row);

    // 如果是预算相关字段变化，同时更新数据库中的预算值
    await updateBudget({
      id: row.id,
      budget: parseFloat(row.budget) || 0,
    });

    // 更新实际费用
    const columnId = tableColumns.value.find(column => column.prop === "actualPay")?.id;
    const cellInfo = {
      id: '',
      budgetId: row.id,
      columnsId: columnId,
      rowId: row.rowId,
      content: row.actualPay,
    };
    await saveOrUpdateBudgets([cellInfo]);
  }

  // 重新获取表格数据
  await getTableData();

  // 数据更新完成后重新初始化拖拽功能
  await nextTick();
  setTimeout(() => {
    initRowDrag();
  }, 100);

  ElMessage.success('内容保存成功');
}

// 获取单元格信息
function getCellInfo(row, prop) {
  return row.colMap?.[prop] ?? "";
}

// 取消编辑
const cancelEditing = () => {
  stopEditing()
}

// 是否可编辑
const isCellEditing = (rowIndex, prop) => {
  return editingCell.rowIndex === rowIndex && editingCell.prop === prop
}

// 是否可编辑
const isEditable = (row, prop, rowIndex) => {
  if (prop === 'id' || prop === 'rowId') return false; // 不允许编辑 ID、rowId
  if (row.type === 1 && prop === 'budget') return false; // 小节行的预算字段不可编辑
  if (row.hasChild === '1' || row.hasChild === 1) return false; // 如果当前行有子项，整行都不能编辑
  return true;
}

// 计算显示的列
const displayedColumns = computed(() => {
  const columns = tableColumns.value.filter(col => selectedColumns.value.includes(col.prop))

  // 计算可用宽度（减去固定列和边距）
  const availableWidth = window.innerWidth - 140 // 减去左侧边距和右侧边距
  const fixedColumns = columns.filter(col => col.fixed)
  const flexibleColumns = columns.filter(col => !col.fixed)

  // 计算固定列的总宽度
  const fixedWidth = fixedColumns.reduce((sum, col) => sum + (col.width || 0), 0)

  // 计算剩余宽度
  const remainingWidth = availableWidth - fixedWidth

  // 为灵活列分配剩余宽度
  if (flexibleColumns.length > 0) {
    const avgWidth = Math.max(remainingWidth / flexibleColumns.length, 120) // 最小宽度120px

    flexibleColumns.forEach(col => {
      col.width = Math.floor(avgWidth)
    })
  }

  return columns
})

// 检查表格实际渲染数据
const filteredTableData = computed(() => {
  if (!searchKeyword.value) {
    return tableData.value
  }

  return tableData.value.filter(row => {
    return Object.values(row).some(value =>
        String(value).toLowerCase().includes(searchKeyword.value.toLowerCase())
    )
  })
})

// 判断是否为固定列（颜色和#ID列）
const isFixedColumn = (prop) => {
  return prop === 'color' || prop === 'rowId'
}

// 临时列选择变化处理
const handleTempColumnChange = () => {
  // 确保固定列始终被选中
  const fixedColumns = ['color', 'rowId']
  fixedColumns.forEach(prop => {
    if (!tempSelectedColumns.value.includes(prop)) {
      tempSelectedColumns.value.push(prop)
    }
  })
}

// 打开列配置弹窗
const openColumnConfig = () => {
  tempSelectedColumns.value = [...selectedColumns.value]
  showColumnConfigDialog.value = true
}

// 取消列配置
const cancelColumnConfig = () => {
  showColumnConfigDialog.value = false
  tempSelectedColumns.value = [...selectedColumns.value]
}

// 确认列配置
const confirmColumnConfig = () => {
  selectedColumns.value = [...tempSelectedColumns.value]
  showColumnConfigDialog.value = false
}

// 总计计算
const totalBudget = computed(() => {
  return filteredTableData.value.reduce((sum, row) => {
    if (row.type !== 1) {  // 排除 type=1 的行
      const budget = parseFloat(row.budget) || 0
      return sum + budget
    }
    return sum;
  }, 0)
})

const totalActual = computed(() => {
  return filteredTableData.value.reduce((sum, row) => {
    if (row.type !== 1) {  // 排除 type=1 的行
      const actual = parseFloat(row.actualPay) || 0
      return sum + actual
    }
    return sum;
  }, 0)
})

const totalVariance = computed(() => {
  return totalActual.value - totalBudget.value
})

// 更新备用金比例
const updateSpareMoneyRatio = async (newRatio) => {
  try {
    // 更新本地状态
    spareMoneyRatio.value = newRatio

    // 更新项目信息
    await updateProject({
      id: queryParams.projectId,
      spareMoneyRatio: newRatio
    })

    ElMessage.success('备用金比例更新成功')
  } catch (error) {
    console.error('更新备用金比例失败:', error)
    ElMessage.error('更新备用金比例失败')
  }
}

const onActiveColorChange = (row, color) => {
  const index = tableData.value.findIndex(r => r.id === row.id);
  if (index !== -1) {
    // 替换整行对象，触发响应式更新
    tableData.value[index] = {
      ...tableData.value[index],
      color: color
    };
  }
}

// 保存颜色（当确认选择后）
const onColorChange = async (row, index) => {
  try {
    // 只更新颜色字段，避免覆盖其他字段
    await updateBudget({
      id: row.id,
      color: row.color
    });
    // 更新本地数据以确保UI同步
    const rowIndex = tableData.value.findIndex(item => item.id === row.id);
    if (rowIndex !== -1) {
      tableData.value[rowIndex].color = row.color;
    }
    // 强制重新渲染表格
    await nextTick();
    ElMessage.success('保存颜色成功');
  } catch (error) {
    ElMessage.error('保存颜色失败');
  }
};

// 单位变化处理
const onUnitChange = async (row) => {
  stopEditing();
}

// 货币转换函数
const convertCurrency = (value, fromCurrency = 'CNY', toCurrency = null) => {
  if (value === null || value === undefined || value === '') {
    return 0;
  }
  const numValue = parseFloat(value);
  if (isNaN(numValue)) {
    return 0;
  }

  const targetCurrency = toCurrency || currentCurrency.value;
  if (fromCurrency === targetCurrency) {
    return numValue;
  }

  const fromRate = exchangeRates.value[fromCurrency] || 1.0;
  const toRate = exchangeRates.value[targetCurrency] || 1.0;

  // 先转换为基准货币（人民币），再转换为目标货币
  const baseValue = numValue / fromRate;
  return baseValue * toRate;
}

// 判断是否为货币列
const isCurrencyColumn = (prop) => {
  const currencyColumns = ['budget', 'actualPay', 'extraPay', 'unitPrice'];
  return currencyColumns.includes(prop);
}


// 格式化预算值显示（带货币符号）
const formatBudgetValue = (value) => {
  if (value === null || value === undefined || value === '') {
    return `${currencySymbols.value[currentCurrency.value]}0.00`;
  }
  const numValue = parseFloat(value);
  if (isNaN(numValue)) {
    return `${currencySymbols.value[currentCurrency.value]}0.00`;
  }

  // 转换为当前选择的货币
  const convertedValue = convertCurrency(numValue);
  return `${currencySymbols.value[currentCurrency.value]}${convertedValue.toFixed(2)}`;
}

// 格式化货币值显示（带货币符号）
const formatCurrencyValue = (value) => {
  if (value === null || value === undefined || value === '') {
    return `${currencySymbols.value[currentCurrency.value]}0.00`;
  }
  const numValue = parseFloat(value);
  if (isNaN(numValue)) {
    return `${currencySymbols.value[currentCurrency.value]}0.00`;
  }

  // 转换为当前选择的货币
  const convertedValue = convertCurrency(numValue);
  return `${currencySymbols.value[currentCurrency.value]}${convertedValue.toFixed(2)}`;
}

// 处理数值输入失去焦点时的格式化
const handleNumberBlur = (row, prop) => {
  const columnData = tableColumns.value.find(col => col.prop === prop);
  if (!columnData || !['int', 'float', 'double', 'long'].includes(columnData.columnType)) {
    stopEditing();
    return;
  }

  const value = row[prop];
  if (value === '' || value === null || value === undefined) {
    stopEditing();
    return;
  }

  // 数值校验和格式化
  const numValue = parseFloat(value);
  if (!isNaN(numValue)) {
    // 如果是货币列，直接存储输入的值（已经是人民币）
    if (isCurrencyColumn(prop)) {
      row[prop] = numValue.toFixed(2);
    } else {
      if (['float', 'double'].includes(columnData.columnType)) {
        // 浮点数保留2位小数
        row[prop] = numValue.toFixed(2);
      } else {
        // 整数类型
        row[prop] = Math.round(numValue).toString();
      }
    }
  }

  stopEditing();
}

// 货币切换处理
const handleCurrencyChange = (currency) => {
  store.commit('setCurrentCurrency', currency);
  currentCurrency.value = currency;
  ElMessage.success(`已切换到${currencyNames.value[currency]}`);
}

// 获取编辑时的数值（显示基准货币原始值）
const getEditingValue = (row, prop) => {
  if (isCurrencyColumn(prop)) {
    // 所有货币列编辑时都显示原始值（人民币）
    const baseValue = parseFloat(row[prop]);
    // 如果值有效，返回原始值而不是格式化后的值
    if (!isNaN(baseValue)) {
      return baseValue.toString();
    }
    return '';
  }
  return row[prop] || '';
}

// 设置编辑时的数值（临时存储，不立即转换）
const setEditingValue = (row, prop, value) => {
  row[prop] = value;
}

// 处理数值输入
const handleNumberInput = (row, prop, event) => {
  const columnData = tableColumns.value.find(col => col.prop === prop);
  if (!columnData || !['int', 'float', 'double', 'long'].includes(columnData.columnType)) {
    return;
  }

  let value = event.target.value;

  // 允许输入数字、小数点和负号，但不做过多限制，让用户可以正常输入小数
  // 只在最终保存时进行严格的数值验证
  setEditingValue(row, prop, value);
};

// 打开汇率管理弹窗
const openExchangeRateDialog = () => {
  tempExchangeRates.value = {...exchangeRates.value};
  showExchangeRateDialog.value = true;
}

// 取消汇率配置
const cancelExchangeRateConfig = () => {
  showExchangeRateDialog.value = false;
  tempExchangeRates.value = {};
}

// 确认汇率配置
const confirmExchangeRateConfig = () => {
  store.commit('setExchangeRates', tempExchangeRates.value);
  showExchangeRateDialog.value = false;
  ElMessage.success('汇率更新成功');
}

// 导出功能
const openExportDialog = () => {
  showExportDialog.value = true;
}

// 导出数据
const exportToExcel = async () => {
  try {
    let dataToExport = [];

    if (exportRange.value === 'all') {
      // 1. 请求完整树形数据
      const res = await queryBudget({
        projectId: queryParams.projectId,
        templateId: queryParams.templateId,
        parentId: 0,
        showChildren: true // 确保后端返回 children
      });

      if (!Array.isArray(res)) {
        ElMessage.warning('未获取到数据');
        return;
      }

      // 2. 递归拍平
      const processedRows = [];
      const traverse = (items, level = 0) => {
        items.forEach(item => {
          const row = {
            id: item.id,
            rowId: item.rowId,
            type: item.type,
            parentId: item.parentId,
            color: item.color,
            content: item.content,
            budget: item.budget,
            visible: item.visible,
            fixed: item.fixed,
            hasChild: !!item.children?.length,
            level,
            sort: item.sort ?? 999999,
            uint: item.uint || '时',
            oldUnit: item.uint || '时',
            // 映射动态列
            ...Object.keys(item.colNameToContent || {}).reduce((acc, colName) => {
              acc[colName] = item.colNameToContent[colName]?.content ?? '';
              return acc;
            }, {})
          };

          processedRows.push(row);

          // 递归子项
          if (Array.isArray(item.children) && item.children.length > 0) {
            traverse(item.children, level + 1);
          }
        });
      };

      traverse(res);
      dataToExport = processedRows;

    } else if (exportRange.value === 'filtered') {
      dataToExport = [...filteredTableData.value]; // 浅拷贝
    } else if (exportRange.value === 'selected' && selectedRow.value) {
      dataToExport = [selectedRow.value];
    }

    // 过滤：只导出 type === 0
    dataToExport = dataToExport.filter(row => row.type === 0);

    if (dataToExport.length === 0) {
      ElMessage.warning('没有可导出的数据（只导出普通行，不包含小节行）');
      return;
    }

    // 生成文件名
    const fileName = `预算数据_${projectName.value}_${new Date().toISOString().slice(0, 10)}.${exportFormat.value}`;

    if (exportFormat.value === 'pdf') {
      exportToPDF(dataToExport, fileName);
    } else {
      const exportData = prepareExportData(dataToExport);

      const wb = XLSX.utils.book_new();
      const ws = XLSX.utils.json_to_sheet(exportData);

      // 设置列宽
      ws['!cols'] = tableColumns.value.map(col => ({
        wch: col.width ? col.width / 8 : 15
      }));

      XLSX.utils.book_append_sheet(wb, ws, '预算数据');
      const wbout = XLSX.write(wb, {bookType: exportFormat.value, type: 'array'});
      const blob = new Blob([wbout], {type: 'application/octet-stream'});
      saveAs(blob, fileName);
    }

    showExportDialog.value = false;
    ElMessage.success('导出成功');
  } catch (error) {
    console.error('导出失败:', error);
    ElMessage.error('导出失败，请重试');
  }
};

// 准备导出数据
const prepareExportData = (data) => {
  return data.map(row => {
    const exportRow = {};

    if (exportRange.value === 'all') {
      exportRow['层级'] = row.level;
    }

    // 添加所有列数据，排除颜色列
    tableColumns.value.forEach(col => {
      if (col.prop === 'budget') {
        // 预算列使用当前货币显示
        exportRow[col.label] = formatBudgetValue(row[col.prop]);
      } else if (isCurrencyColumn(col.prop)) {
        // 货币列使用当前货币显示
        exportRow[col.label] = formatCurrencyValue(row[col.prop]);
      } else if (col.prop === 'color') {
        // 跳过颜色列，不进行导出

      } else {
        exportRow[col.label] = row[col.prop] || '';
      }
    });

    return exportRow;
  });
}

// PDF导出功能
const exportToPDF = (data, fileName) => {
  try {
    // 创建PDF文档
    const doc = new jsPDF('l', 'mm', 'a4'); // 横向A4纸张

    doc.setFont('AlibabaPuHuiTi-3-45-Light');

    // 添加标题
    doc.setFontSize(16);
    doc.text(`${projectName.value} - 预算数据报表`, 20, 20);

    // 添加导出信息
    doc.setFontSize(10);
    const currentDate = new Date().toLocaleString('zh-CN');
    const currencyName = currencyNames.value[currentCurrency.value];
    doc.text(`导出时间: ${currentDate}`, 20, 30);
    doc.text(`货币单位: ${currencyName}`, 20, 35);
    doc.text(`数据条数: ${data.length} 条`, 20, 40);

    // 准备表格数据
    const tableData = preparePDFTableData(data);
    console.log(tableData);
    const columns = preparePDFColumns();

    // 使用autoTable插件生成表格
    autoTable(doc, {
      head: [columns],
      body: tableData,
      startY: 50,
      margin: {left: 20, right: 20},
      styles: {
        font: 'AlibabaPuHuiTi-3-45-Light',  // 确保表格数据使用中文字体
        fontSize: 8,
        cellPadding: 2,
        fontStyle: 'normal'
      },
      headStyles: {
        fillColor: [64, 158, 255],
        textColor: 255,
        fontStyle: 'normal',
        font: 'AlibabaPuHuiTi-3-45-Light',
        halign: 'center'
      },
      alternateRowStyles: {
        fillColor: [245, 247, 250]
      },
      tableLineColor: [220, 223, 230],
      tableLineWidth: 0.1,
      // 添加字体配置确保一致性
      didParseCell: function (data) {
        // 确保所有单元格都使用中文字体
        data.cell.styles.font = 'AlibabaPuHuiTi-3-45-Light';
      }
    });

    // 保存文件
    doc.save(fileName);
  } catch (error) {
    console.error('PDF导出失败:', error);
    ElMessage.error('PDF导出失败，请重试');
  }
}

// 准备PDF表格列
const preparePDFColumns = () => {
  // 过滤掉颜色列，只保留需要显示的列
  return tableColumns.value
      .filter(col => col.prop !== 'color' && selectedColumns.value.includes(col.prop))
      .map(col => col.label);
}

// 准备PDF表格数据
const preparePDFTableData = (data) => {
  // 获取要显示的列（过滤掉颜色列，只保留选中的列）
  const visibleColumns = tableColumns.value.filter(
      col => col.prop !== 'color' && selectedColumns.value.includes(col.prop)
  );

  return data.map(row => {
    const tableRow = [];

    // 使用过滤后的列来构建数据行，确保数据与列标题一一对应
    visibleColumns.forEach(col => {
      let cellValue = '';

      if (col.prop === 'budget') {
        // 预算列使用当前货币显示
        cellValue = formatBudgetValue(row[col.prop]);
      } else if (isCurrencyColumn(col.prop)) {
        // 货币列使用当前货币显示
        cellValue = formatCurrencyValue(row[col.prop]);
      } else {
        // 其他列，确保是字符串类型
        const value = row[col.prop];
        cellValue = value !== null && value !== undefined ? String(value) : '';
      }

      // 确保单元格值不为undefined或null
      tableRow.push(cellValue || '');
    });

    return tableRow;
  });
}

// 导入功能
const openImportDialog = () => {
  showImportDialog.value = true;
}

const handleFileUpload = (file) => {
  // Element Plus 的 on-change 事件传递的是文件对象，包含 raw 属性
  const actualFile = file.raw || file;
  importFile.value = actualFile;

  // 检查文件类型
  if (!actualFile || !(actualFile instanceof File)) {
    ElMessage.error('请选择有效的文件');
    return;
  }

  // 检查文件扩展名
  const fileName = actualFile.name.toLowerCase();
  if (!fileName.endsWith('.xlsx') && !fileName.endsWith('.xls') && !fileName.endsWith('.csv')) {
    ElMessage.error('请选择 Excel 文件（.xlsx, .xls）或 CSV 文件（.csv）');
    return;
  }

  // 读取文件
  const reader = new FileReader();
  reader.onload = (e) => {
    try {
      const data = new Uint8Array(e.target.result);
      const workbook = XLSX.read(data, {type: 'array'});
      const sheetName = workbook.SheetNames[0];
      const worksheet = workbook.Sheets[sheetName];
      const jsonData = XLSX.utils.sheet_to_json(worksheet);

      // 验证和转换数据
      const validatedData = validateImportData(jsonData);
      importData.value = validatedData.validData;
      importPreviewData.value = validatedData.validData.slice(0, 10); // 只显示前10行预览

      console.log('导入数据验证结果:', {
        totalRows: jsonData.length,
        validData: validatedData.validData.length,
        errors: validatedData.errors.length,
        previewData: importPreviewData.value.length
      });

      // 显示解析成功消息
      ElMessage.success(`文件解析成功，共解析 ${validatedData.validData.length} 条数据，请在预览页面检查和编辑数据`);

      // 确保有数据才显示预览
      if (validatedData.validData.length > 0) {
        showImportDialog.value = false;
        showImportPreviewDialog.value = true;
      } else {
        ElMessage.error('没有数据可以导入，请检查文件内容');
      }
    } catch (error) {
      console.error('文件解析失败:', error);
      ElMessage.error('文件解析失败，请检查文件格式');
    }
  };

  reader.onerror = () => {
    ElMessage.error('文件读取失败');
  };

  reader.readAsArrayBuffer(actualFile);
}

// 验证导入数据 - 宽松模式，尽量不报错
const validateImportData = (data) => {
  const validData = [];
  const errors = [];

  data.forEach((row, index) => {
    const validRow = {};

    // 使用更灵活的字段匹配，不进行严格验证
    const rowIdValue = row.rowId || row['# ID'] || row['ID'] || row['id'] || row['行ID'] || '';
    const budgetValue = row.budget || row['预算'] || row['Budget'] || row['BUDGET'] || row['金额'] || '';

    // 转换数据格式，不进行严格验证
    validRow.id = row.id || '';
    validRow.rowId = rowIdValue;
    validRow.type = row.type || 0;
    validRow.parentId = row.parentId || 0;

    // 尝试转换预算值，如果失败则设为0
    const budgetNum = parseFloat(budgetValue);
    validRow.budget = isNaN(budgetNum) ? 0 : budgetNum;
    validRow.hasChild = row.hasChild || '0';
    validRow.sort = row.sort || (validData.length + 1);

    // 添加其他列数据，排除颜色列
    tableColumns.value.forEach(col => {
      if (col.prop !== 'id' && col.prop !== 'rowId' && col.prop !== 'type' &&
          col.prop !== 'parentId' && col.prop !== 'color' && col.prop !== 'budget' &&
          col.prop !== 'visible' && col.prop !== 'fixed' && col.prop !== 'hasChild' &&
          col.prop !== 'sort') {
        // 尝试多种字段名匹配
        validRow[col.prop] = row[col.label] || row[col.prop] || row[col.label.toLowerCase()] ||
            row[col.prop.toLowerCase()] || row[col.label.toUpperCase()] ||
            row[col.prop.toUpperCase()] || '';
      }
    });

    validData.push(validRow);
  });

  return {validData, errors};
}

// 预览页面校验函数
const validateBudgetValue = (row, index) => {
  const value = parseFloat(row.budget);
  if (isNaN(value) || value < 0) {
    ElMessage.warning(`第${index + 1}行预算值无效，已设为0`);
    row.budget = 0;
  }
}

const validateRowId = (row, index) => {
  if (!row.rowId || row.rowId.trim() === '') {
    ElMessage.warning(`第${index + 1}行ID不能为空，已生成默认ID`);
    row.rowId = `import_${index + 1}`;
  }
}

// 最终导入校验
const validateImportDataFinal = () => {
  const errors = [];

  importData.value.forEach((row, index) => {
    const rowErrors = [];

    // 校验必填字段
    if (!row.rowId || row.rowId.trim() === '') {
      rowErrors.push('行ID不能为空');
    }

    // 校验预算值
    const budgetValue = parseFloat(row.budget);
    if (isNaN(budgetValue) || budgetValue < 0) {
      rowErrors.push('预算必须是有效的非负数');
    }

    if (rowErrors.length > 0) {
      errors.push({
        row: index + 1,
        errors: rowErrors
      });
    }
  });

  return errors;
}

// 确认导入
const confirmImport = () => {
  try {
    // 进行最终校验
    const validationErrors = validateImportDataFinal();

    if (validationErrors.length > 0) {
      // 显示校验错误
      const errorMessage = validationErrors.map(error =>
          `第${error.row}行: ${error.errors.join(', ')}`
      ).join('\n');

      ElMessageBox.confirm(
          `发现以下数据错误，是否继续导入？\n\n${errorMessage}`,
          '数据校验警告',
          {
            confirmButtonText: '继续导入',
            cancelButtonText: '取消',
            type: 'warning',
            dangerouslyUseHTMLString: false
          }
      ).then(() => {
        // 用户确认继续导入
        performImport();
      }).catch(() => {
        // 用户取消导入
        ElMessage.info('已取消导入');
      });
    } else {
      // 没有错误，直接导入
      performImport();
    }
  } catch (error) {
    console.error('导入失败:', error);
    ElMessage.error('导入失败，请重试');
  }
}

// 执行导入操作
const performImport = () => {
  try {
    // 将导入的数据添加到表格中
    importData.value.forEach(row => {
      // 转换预算值为基准货币（人民币）
      if (row.budget) {
        row.budget = convertCurrency(row.budget, currentCurrency.value, 'CNY').toFixed(2);
      }
      tableData.value.push(row);
    });

    showImportPreviewDialog.value = false;
    ElMessage.success(`成功导入 ${importData.value.length} 条数据`);

    // 清空导入数据
    importData.value = [];
    importPreviewData.value = [];
    importFile.value = null;
  } catch (error) {
    console.error('导入失败:', error);
    ElMessage.error('导入失败，请重试');
  }
}

// 取消导入
const cancelImport = () => {
  showImportPreviewDialog.value = false;
  importData.value = [];
  importPreviewData.value = [];
  importFile.value = null;
}

</script>


<style scoped>
.context-menu {
  position: absolute;
  background-color: #fff;
  border: 1px solid #e4e7ed;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  z-index: 9999;
  list-style: none;
  padding: 6px 0;
  margin: 0;
  width: 160px;
  border-radius: 6px;
  font-size: 14px;
}

.context-menu li {
  padding: 10px 16px;
  cursor: pointer;
  transition: all 0.2s ease;
  display: flex;
  align-items: center;
  gap: 8px;
  color: #606266;
}

.context-menu li:hover {
  background-color: #f5f7fa;
  color: #409eff;
}

.context-menu li.danger {
  color: #f56c6c;
}

.context-menu li.danger:hover {
  background-color: #fef0f0;
  color: #f56c6c;
}

.context-menu li.divider {
  height: 1px;
  background-color: #e4e7ed;
  margin: 4px 0;
  padding: 0;
  cursor: default;
}

.context-menu li.divider:hover {
  background-color: #e4e7ed;
}

.container {
  position: relative;
  max-width: 100%;
  height: 100%;
  margin: 0;
  display: flex;
  flex-direction: column;
  background-color: #ffffff;
}

.header-section {
  background: #ffffff;
  padding: 20px 24px;
  border-bottom: 1px solid #f0f0f0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
}

.header-left {
  display: flex;
  align-items: center;
}

.project-title {
  margin: 0;
  color: #1a1a1a;
  font-size: 22px;
  font-weight: 500;
  letter-spacing: -0.5px;
  cursor: pointer;
}

.header-right {
  display: flex;
  align-items: center;
}

.header-controls {
  display: flex;
  gap: 16px;
  align-items: center;
}

.navigation-path {
  display: flex;
  align-items: center;
  margin-top: 8px;
  font-size: 14px;
  color: #909399;
}

.path-label {
  margin-right: 8px;
}

.path-item {
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 4px;
}

.path-item:hover {
  color: #409eff;
}

.path-item.current-level {
  color: #1a1a1a;
  font-weight: 600;
}

.path-separator {
  font-size: 12px;
}


.footer-section {
  position: fixed;
  bottom: 0;
  left: 70px;
  right: 0;
  background: #ffffff;
  padding: 10px 24px 10px 34px;
  border-top: 1px solid #f0f0f0;
  display: flex;
  justify-content: left;
  gap: 24px;
  align-items: center;
  box-shadow: 0 -1px 3px rgba(0, 0, 0, 0.05);
  z-index: 1000;
}

.total-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 0;
}

.total-label {
  font-weight: 500;
  color: #666666;
  font-size: 14px;
}

.total-value {
  font-weight: 600;
  color: #1a1a1a;
  font-size: 15px;
  min-width: 100px;
  text-align: right;
}

.total-value.positive {
  color: #67c23a;
}

.total-value.negative {
  color: #f56c6c;
}

.spare-money {
  display: flex;
  align-items: center;
  gap: 8px;
}

.edit-ratio-btn {
  padding: 4px;
  height: 24px;
  width: 24px;
}

.spare-money-editor {
  padding: 10px;
}

.editor-title {
  font-weight: bold;
  margin-bottom: 15px;
  text-align: center;
}

.editor-content {
  padding: 0 10px;
}

.total-with-spare {
  color: #409eff;
  font-weight: bold;
}

.variance {
  padding-left: 24px;
  border-left: 1px solid #e0e0e0;
}

.table-wrapper {
  height: 100%;
  overflow-x: auto;
  overflow-y: auto;
  min-height: 0;
  background: #ffffff;
  width: 100%;
  margin-bottom: 60px;
}

::v-deep(.custom-hover-table .el-table__body tr:hover) {
  background-color: #f8f9fa !important;
  transition: background-color 0.2s ease;
}

::v-deep(.custom-hover-table .el-table__body td) {
  transition: all 0.2s ease;
  padding: 8px 0;
}

::v-deep(.custom-hover-table .el-table__body td:hover) {
  background-color: #f8f9fa;
}

::v-deep(.custom-hover-table .el-table__body td .editable-cell) {
  margin: -8px 0;
}

::v-deep(.custom-hover-table .el-table__body td .editable-cell.editing-cell) {
  margin: -6px 0;
}

.editable-cell {
  padding: 6px 8px;
  cursor: pointer;
  transition: all 0.2s ease;
  min-height: 20px;
  display: flex;
  align-items: center;
}

.editable-cell,
::v-deep(.full-cell-input .el-input__wrapper),
::v-deep(.full-cell-input .el-input__inner) {
  height: 40px !important;
  min-height: 40px !important;
  line-height: 40px !important;
  box-sizing: border-box;
}

.editable-cell {
  padding: 0 !important;
}

::v-deep(.el-table__body tr) {
  height: 40px;
  min-height: 40px;
  max-height: 40px;
}


.editable-cell.editing-cell .el-input {
  width: 100%;
}

.editable-cell.editing-cell .el-input__inner {
  border: none;
  background: transparent;
  padding: 0;
  font-size: inherit;
  color: inherit;
  box-shadow: none;
}

.editable-cell.editing-cell .el-input__inner:focus {
  box-shadow: none;
  border: none;
}

/* 优化输入框清除按钮样式 */
.editable-cell.editing-cell .el-input__suffix {
  right: 4px;
}

.editable-cell.editing-cell .el-input__suffix .el-input__clear {
  color: #c0c4cc;
  font-size: 12px;
}

.editable-cell.editing-cell .el-input__suffix .el-input__clear:hover {
  color: #909399;
}

/* 确保编辑状态下的文本对齐 */
.editable-cell.editing-cell .el-input__inner {
  text-align: inherit;
}

::v-deep(.no-border-input .el-input__wrapper) {
  box-shadow: none !important;
  border: none !important;
  background: transparent !important;
}

::v-deep(.no-border-input .el-input__inner) {
  border: none !important;
  background: transparent !important;
  box-shadow: none !important;
}

::v-deep(.full-cell-input .el-input__wrapper) {
  width: 100% !important;
  height: 100% !important;
  min-height: 32px;
  background: #f7fafc;
  padding: 0;
  box-shadow: none !important;
}

::v-deep(.full-cell-input .el-input__inner) {
  width: 100% !important;
  height: 100% !important;
  background: transparent;
  border: none;
  box-shadow: none;
  font-size: 15px;
}

.color-cell {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

.color-cell .el-color-picker {
  vertical-align: middle;
}

.color-preview {
  display: inline-block;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 1.5px solid #e0e0e0;
  margin-left: 2px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
}

::v-deep(.el-table__body tr.sortable-ghost) {
  opacity: 0.5;
  background: #c8ebfb !important;
}

::v-deep(.el-table__body tr.sortable-chosen) {
  background: #f0f9ff !important;
}

::v-deep(.el-table__body tr.sortable-drag) {
  background: #e6f7ff !important;
}

.drag-handle {
  cursor: move;
  color: #909399;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
}

.drag-handle:hover {
  color: #409EFF;
}

/* 选中行的样式 */
::v-deep(.selected-row) {
  background-color: #e6f7ff !important;
}

::v-deep(.selected-row td) {
  background-color: #e6f7ff !important;
}

::v-deep(.selected-row:hover td) {
  background-color: #d1f2ff !important;
}

/* 表格边框样式 */
::v-deep(.el-table) {
  border: 1px solid #ebeef5;
}

::v-deep(.el-table__inner-wrapper::before),
::v-deep(.el-table__inner-wrapper::after) {
  display: none;
}

/* 确保数据行表格与表头宽度一致 */
.draggable-table .el-table {
  width: 100% !important;
}

.draggable-table .el-table .el-table__body {
  width: 100% !important;
}

/* 确保表头和数据行对齐 */
.header-table .el-table__header,
.header-table .el-table__body,
.header-table .el-table__footer {
  table-layout: auto !important;
  width: 100% !important;
}

.header-table .el-table__header-wrapper {
  position: static;
}

/* 确保表头和数据行对齐 */
.header-table .el-table__header,
.header-table .el-table__body,
.header-table .el-table__footer {
  table-layout: auto !important;
  width: 100% !important;
}

.header-table .el-table__inner-wrapper::before {
  display: none;
}

/* 确保表头始终显示 */
.header-table .el-table__header-wrapper th {
  background: #f5f7fa;
  font-weight: 600;
  color: #606266;
  padding: 12px 0;
  border-bottom: 1px solid #ebeef5;
}

/* 调整表格内容的样式 */
.el-table .cell {
  padding: 0 !important;
}

/* 确保表格单元格边框显示 */
::v-deep(.el-table td) {
  border-bottom: 1px solid #ebeef5;
}

::v-deep(.el-table th) {
  border-bottom: 1px solid #ebeef5;
}

/* 确保表格行高度一致 */
.el-table__row {
  height: 40px;
}

.mb-1 {
  margin-bottom: 1px;
}

/* 列分割线样式 */
::v-deep(.el-table__cell) {
  border-right: 1px solid #ebeef5;
}

::v-deep(.el-table__cell:last-child) {
  border-right: none;
}

/* 表头分割线 */
::v-deep(.el-table__header th) {
  border-right: 1px solid #ebeef5;
}

::v-deep(.el-table__header th:last-child) {
  border-right: none;
}

/* 确保列宽调整功能正常工作 */
::v-deep(.el-table) {
  table-layout: auto;
}

/* 调整列宽拖拽手柄样式 */
::v-deep(.el-table__column-resize-proxy) {
  background-color: #409eff;
  width: 2px;
  z-index: 1000;
}

/* 列宽调整手柄样式 */
::v-deep(.el-table__column-resize-handle) {
  background-color: #409eff;
  width: 2px;
  cursor: col-resize;
}

/* 确保表格支持列宽调整 */
::v-deep(.el-table) {
  table-layout: auto;
}

/* 清除 td 背景，让 tr 背景可见 */
::v-deep(.el-table__row td) {
  background-color: transparent !important;
}

/* 调整列宽拖拽手柄样式 */
::v-deep(.el-table__column-resize-proxy) {
  background-color: #409eff;
  width: 2px;
}

/* 列宽调整时的视觉反馈 */
::v-deep(.el-table__body-wrapper:hover .el-table__cell) {
  border-right-color: #c0c4cc;
}

/* 确保表格边框样式 */
::v-deep(.el-table) {
  border: 1px solid #ebeef5;
}

::v-deep(.el-table td) {
  border: 1px solid #ebeef5;
}

::v-deep(.el-table__inner-wrapper::before) {
  display: none;
}

::v-deep(.el-table__inner-wrapper::after) {
  display: none;
}

/* 合并单元格样式 */
::v-deep(.el-table__cell.is-hidden) {
  display: none;
}

/* 小节行样式 */
.section-row {
  background-color: #f8f9fa !important;
  font-weight: 600;
}

/* 合并后的单元格样式 */
::v-deep(.el-table__cell[colspan]) {
  background-color: #f8f9fa;
  border-right: 1px solid #ebeef5;
}

/* 确保预算列在小节行中正常显示 */
::v-deep(.el-table__cell:has(.budget-cell)) {
  background-color: #ffffff;
}

/* 财务输入字段样式 */
.budget-input-with-unit .el-input__inner {
  text-align: right;
  padding-right: 8px;
}

.budget-input-with-unit .el-input-group__append {
  background-color: #f5f7fa;
  border-left: 1px solid #dcdfe6;
  color: #909399;
  font-size: 12px;
  font-weight: 500;
  padding: 0 8px;
  min-width: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* 单位下拉选择器样式 */
.full-cell-input .el-select {
  width: 100% !important;
}

.full-cell-input .el-select .el-input__wrapper {
  width: 100% !important;
  height: 40px !important;
  min-height: 40px !important;
  background: #f7fafc;
  box-shadow: none !important;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
}

.full-cell-input .el-select .el-input__inner {
  width: 100% !important;
  height: 100% !important;
  background: transparent;
  border: none;
  box-shadow: none;
  font-size: 14px;
  text-align: center;
  padding: 0 8px;
}

.full-cell-input .el-select .el-input__suffix {
  right: 8px;
}

.full-cell-input .el-select:hover .el-input__wrapper {
  border-color: #409eff;
  box-shadow: 0 0 0 1px #409eff20;
}

.full-cell-input .el-select.is-focused .el-input__wrapper {
  border-color: #409eff;
  box-shadow: 0 0 0 1px #409eff40;
}

/* 列配置弹窗样式 */
.column-config-content {
  padding: 10px 0;
}

.config-header {
  margin-bottom: 15px;
}

.config-title {
  font-size: 14px;
  font-weight: 500;
  color: #303133;
}

.column-list {
  max-height: 300px;
  overflow-y: auto;
}

.column-item {
  padding: 8px 0;
  border-bottom: 1px solid #f0f0f0;
}

.column-item:last-child {
  border-bottom: none;
}

.column-item.disabled {
  opacity: 0.8;
}

.fixed-label {
  color: #909399;
  font-size: 12px;
  margin-left: 5px;
}

.dialog-footer {
  text-align: right;
}

/* 汇率管理弹窗样式 */
.exchange-rate-content {
  padding: 10px 0;
}

.rate-header {
  margin-bottom: 20px;
}

.rate-title {
  font-size: 14px;
  font-weight: 500;
  color: #303133;
}

.rate-list {
  max-height: 300px;
  overflow-y: auto;
}

.rate-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 0;
  border-bottom: 1px solid #f0f0f0;
}

.rate-item:last-child {
  border-bottom: none;
}

.rate-label {
  display: flex;
  align-items: center;
  gap: 8px;
}

.currency-symbol {
  font-size: 16px;
  font-weight: 600;
  color: #409eff;
  min-width: 20px;
}

.currency-name {
  font-size: 14px;
  color: #606266;
}

.rate-note {
  margin-top: 20px;
  padding: 12px;
  background-color: #f5f7fa;
  border-radius: 4px;
  text-align: center;
}

/* 导出弹窗样式 */
.export-content {
  padding: 10px 0;
}

.export-option {
  margin-bottom: 20px;
}

.export-label {
  display: block;
  margin-bottom: 10px;
  font-size: 14px;
  font-weight: 500;
  color: #303133;
}

.export-note {
  margin-top: 20px;
  padding: 12px;
  background-color: #f5f7fa;
  border-radius: 4px;
  text-align: center;
}

/* 导入弹窗样式 */
.import-content {
  padding: 10px 0;
}

.upload-demo {
  width: 100%;
}

/* 导入预览弹窗样式 */
.import-preview-content {
  padding: 10px 0;
}

.preview-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 15px;
}

.preview-title {
  font-size: 14px;
  font-weight: 500;
  color: #303133;
}

.preview-count {
  font-size: 12px;
  color: #909399;
}

.preview-table {
  border: 1px solid #ebeef5;
  border-radius: 4px;
  overflow: hidden;
}
</style>
